home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / PlayTrackInfoThang.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  23.1 KB  |  694 lines  |  [TEXT/KAHL]

  1. /* PlayTrackInfoThang.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "PlayTrackInfoThang.h"
  31. #include "Array.h"
  32. #include "Memory.h"
  33. #include "OscBankPlayer.h"
  34. #include "TrackObject.h"
  35. #include "IncrementalParameterUpdator.h"
  36. #include "Fractions.h"
  37. #include "FrameObject.h"
  38. #include "DeterminedNoteStructure.h"
  39. #include "NoteObject.h"
  40. #include "ErrorDaemon.h"
  41.  
  42.  
  43. typedef struct FrozenNoteConsCell
  44.     {
  45.         /* list link */
  46.         struct FrozenNoteConsCell*    Next;
  47.  
  48.         /* good information to be used for tied notes */
  49.         FrozenNoteRec*                        FrozenNote;
  50.  
  51.         /* tie target for tied notes, NIL if there is no tie */
  52.         struct NoteObjectRec*            TieTarget;
  53.  
  54.         /* when this note should take over (in absolute envelope ticks) */
  55.         long                                            ContinuationTime;
  56.     } FrozenNoteConsCell;
  57.  
  58.  
  59. typedef struct OscBankConsCell
  60.     {
  61.         /* link for listing */
  62.         struct OscBankConsCell*        Next;
  63.         struct OscBankConsCell*        Previous;
  64.  
  65.         /* the oscillator bank */
  66.         OscStateBankRec*                    OscBank;
  67.  
  68.         /* still active flag */
  69.         MyBoolean                                    StillActive;
  70.  
  71.         /* tie target for tied notes, NIL if there is no tie */
  72.         struct NoteObjectRec*            TieTarget;
  73.  
  74.         /* this is the start time of the note, used for ordering the scanning gap list */
  75.         long                                            StartTime;
  76.  
  77.         /* this is an ordered list of frozen notes ready for tie continuation */
  78.         /* this is in sorted ascending order of TieContinuationList->ContinuationTime */
  79.         FrozenNoteConsCell*                TieContinuationList;
  80.     } OscBankConsCell;
  81.  
  82.  
  83. struct PlayTrackInfoRec
  84.     {
  85.         /* frame source */
  86.         TrackObjectRec*                    TrackObject;
  87.         /* total number of frames in the track object */
  88.         long                                        TotalNumberOfFrames;
  89.         /* index into frame array. */
  90.         long                                        FrameArrayIndex;
  91.         /* number of cycles until the next frame should be processed.  this is in */
  92.         /* units of duration update cycles.  when this runs out, then another frame */
  93.         /* should be processed. */
  94.         long                                        NextFrameCountDown;
  95.  
  96.         /* list of notes that have been scheduled but haven't been executed yet. */
  97.         /* it contains objects of type OscBankConsCell. */
  98.         OscBankConsCell*                ScanningGapListHead; /* of OscBankConsCell's */
  99.         OscBankConsCell*                ScanningGapListTail; /* of OscBankConsCell's */
  100.         /* this is the current duration update index for the scanning gap list */
  101.         long                                        ExecutionIndex;
  102.         /* this is the index of the first element in the scanning gap list.  when */
  103.         /* the execution index hits or exceeds this value, the first osc bank is popped */
  104.         /* from the scanning gap list and executed.  it is only valid when */
  105.         /* ScanningGapLength is greater than zero (i.e. ScanningGapList is non-empty) */
  106.  
  107.         /* this object keeps track of the current value of all parameters, updates them */
  108.         /* as time passes, and evaluates commands passed in from here. */
  109.         IncrParamUpdateRec*            ParameterController;
  110.  
  111.         /* this is the template used for creating oscillator banks */
  112.         OscBankTemplateRec*            OscillatorBankTemplate;
  113.  
  114.         /* this is a list of all currently executing oscillator banks.  there is one */
  115.         /* entry for each note that is currently being played. */
  116.         OscBankConsCell*                ExecutingOscillatorBanks;
  117.  
  118.         /* playback control parameters */
  119.         float                                        EnvelopeUpdateRate;
  120.         float                                        OverallVolumeScaling;
  121.     };
  122.  
  123.  
  124. static OscBankConsCell*                    OscBankConsCellFreeList = NIL;
  125. struct FrozenNoteConsCell*            FrozenNoteConsCellFreeList = NIL;
  126.  
  127.  
  128. /* dispose of cached track data structures */
  129. void                                FlushPlayTrackInfo(void)
  130.     {
  131.         while (OscBankConsCellFreeList != NIL)
  132.             {
  133.                 OscBankConsCell*        Temp;
  134.  
  135.                 Temp = OscBankConsCellFreeList;
  136.                 OscBankConsCellFreeList = OscBankConsCellFreeList->Next;
  137.                 ReleasePtr((char*)Temp);
  138.             }
  139.  
  140.         while (FrozenNoteConsCellFreeList != NIL)
  141.             {
  142.                 FrozenNoteConsCell*    Temp;
  143.  
  144.                 Temp = FrozenNoteConsCellFreeList;
  145.                 FrozenNoteConsCellFreeList = FrozenNoteConsCellFreeList->Next;
  146.                 ReleasePtr((char*)Temp);
  147.             }
  148.     }
  149.  
  150.  
  151. /* create a new track play info thing and set a bunch of parameters.  this also */
  152. /* builds the internal representations for instruments & oscillators for this track. */
  153. PlayTrackInfoRec*        NewPlayTrackInfo(struct TrackObjectRec* TheTrack,
  154.                                             struct InstrumentRec* InstrumentSpecification,
  155.                                             MyBoolean StereoFlag, LargeBCDType OverallVolumeScalingReciprocal,
  156.                                             long SamplingRate, float EnvelopeRate, MyBoolean TimeInterp,
  157.                                             MyBoolean WaveInterp, struct TempoControlRec* TempoControl,
  158.                                             long ScanningGapWidthInEnvelopeTicks, ErrorDaemonRec* ErrorDaemon)
  159.     {
  160.         PlayTrackInfoRec*    TrackInfo;
  161.  
  162.         CheckPtrExistence(TheTrack);
  163.         CheckPtrExistence(InstrumentSpecification);
  164.         CheckPtrExistence(TempoControl);
  165.         CheckPtrExistence(ErrorDaemon);
  166.  
  167.         TrackInfo = (PlayTrackInfoRec*)AllocPtrCanFail(sizeof(PlayTrackInfoRec),
  168.             "PlayTrackInfoRec");
  169.         if (TrackInfo == NIL)
  170.             {
  171.              FailurePoint1:
  172.                 return NIL;
  173.             }
  174.  
  175.         /* frame source */
  176.         TrackInfo->TrackObject = TheTrack;
  177.  
  178.         /* total number of frames in the track object */
  179.         TrackInfo->TotalNumberOfFrames = TrackObjectGetNumFrames(TheTrack);
  180.  
  181.         /* index into frame array. */
  182.         TrackInfo->FrameArrayIndex = 0;
  183.  
  184.         /* number of cycles until the next frame should be processed.  this is in */
  185.         /* units of duration update cycles.  when this runs out, then another frame */
  186.         /* should be processed. */
  187.         TrackInfo->NextFrameCountDown = 0;
  188.  
  189.         /* list of notes that have been scheduled but haven't been executed yet. */
  190.         /* it contains objects of type OscStateBankRec. */
  191.         TrackInfo->ScanningGapListHead = NIL;
  192.         TrackInfo->ScanningGapListTail = NIL;
  193.  
  194.         /* this is the current envelope update index for removing things from the */
  195.         /* scanning gap list (i.e. the back edge of the scanning gap) */
  196.         TrackInfo->ExecutionIndex = - ScanningGapWidthInEnvelopeTicks;
  197.  
  198.         /* this object keeps track of the current value of all parameters, updates them */
  199.         /* as time passes, and evaluates commands passed in from here. */
  200.         TrackInfo->ParameterController = NewInitializedParamUpdator(TheTrack,TempoControl);
  201.         if (TrackInfo->ParameterController == NIL)
  202.             {
  203.              FailurePoint2:
  204.                 ReleasePtr((char*)TrackInfo);
  205.                 goto FailurePoint1;
  206.             }
  207.  
  208.         /* this is the template used for creating oscillator banks */
  209.         TrackInfo->OscillatorBankTemplate = NewOscBankTemplate(InstrumentSpecification,
  210.             StereoFlag,OverallVolumeScalingReciprocal,SamplingRate,EnvelopeRate,
  211.             TimeInterp,WaveInterp,TrackInfo->ParameterController,ErrorDaemon);
  212.         if (TrackInfo->OscillatorBankTemplate == NIL)
  213.             {
  214.              FailurePoint3:
  215.                 DisposeParamUpdator(TrackInfo->ParameterController);
  216.                 goto FailurePoint2;
  217.             }
  218.  
  219.         /* this is a list of all currently executing oscillator banks.  there is one */
  220.         /* entry for each note that is currently being played. */
  221.         TrackInfo->ExecutingOscillatorBanks = NIL;
  222.  
  223.         /* playback control parameters */
  224.         TrackInfo->EnvelopeUpdateRate = EnvelopeRate;
  225.         TrackInfo->OverallVolumeScaling = (float)1
  226.             / LargeBCD2Double(OverallVolumeScalingReciprocal);
  227.  
  228.         return TrackInfo;
  229.     }
  230.  
  231.  
  232. static void                    DisposeOscBankList(OscBankConsCell* List)
  233.     {
  234.         while (List != NIL)
  235.             {
  236.                 OscBankConsCell*    Temp;
  237.  
  238.                 /* delink */
  239.                 Temp = List;
  240.                 List = List->Next;
  241.                 /* dispose members */
  242.                 DisposeOscStateBank(Temp->OscBank);
  243.                 while (Temp->TieContinuationList != NIL)
  244.                     {
  245.                         FrozenNoteConsCell*        ColdTemp;
  246.  
  247.                         ColdTemp = Temp->TieContinuationList;
  248.                         Temp->TieContinuationList = Temp->TieContinuationList->Next;
  249.                         DisposeFrozenNote(ColdTemp->FrozenNote);
  250.                         ColdTemp->Next = FrozenNoteConsCellFreeList;
  251.                         FrozenNoteConsCellFreeList = ColdTemp;
  252.                     }
  253.                 /* stick on free list */
  254.                 Temp->Next = OscBankConsCellFreeList;
  255.                 EXECUTE(Temp->Previous = (OscBankConsCell*)0x81818181;)
  256.                 OscBankConsCellFreeList = Temp;
  257.             }
  258.     }
  259.  
  260.  
  261. /* dump a track play info thing and all the stuff in it */
  262. void                                DisposePlayTrackInfo(PlayTrackInfoRec* TrackInfo)
  263.     {
  264.         CheckPtrExistence(TrackInfo);
  265.         DisposeOscBankList(TrackInfo->ScanningGapListHead);
  266.         DisposeOscBankList(TrackInfo->ExecutingOscillatorBanks);
  267.         DisposeOscBankTemplate(TrackInfo->OscillatorBankTemplate);
  268.         DisposeParamUpdator(TrackInfo->ParameterController);
  269.         ReleasePtr((char*)TrackInfo);
  270.     }
  271.  
  272.  
  273. /* cue track forward to the specified point.  returns False if it fails */
  274. MyBoolean                        CuePlayTrackInfoToPoint(PlayTrackInfoRec* TrackInfo,
  275.                                             struct FractionRec* StartTime)
  276.     {
  277.         long                            AdvancementCounter;
  278.  
  279.         CheckPtrExistence(TrackInfo);
  280.  
  281.         /* convert whole-note fraction into duration ticks */
  282.         ERROR(StartTime->Denominator != DURATIONUPDATECLOCKRESOLUTION,PRERR(AllowResume,
  283.             "CuePlayTrackInfoToPoint:  start time denominator has bad value"));
  284.         AdvancementCounter = StartTime->Integer * StartTime->Denominator
  285.             + StartTime->Fraction;
  286.  
  287.         /* search for the proper point to start playing */
  288.         while ((AdvancementCounter > 0)
  289.             && (TrackInfo->FrameArrayIndex < TrackInfo->TotalNumberOfFrames))
  290.             {
  291.                 FrameObjectRec*        Frame; /* I've been framed! */
  292.                 FractionRec                Duration;
  293.                 long                            TicksInFrame;
  294.  
  295.                 /* get the frame */
  296.                 Frame = TrackObjectGetFrame(TrackInfo->TrackObject,TrackInfo->FrameArrayIndex);
  297.                 CheckPtrExistence(Frame);
  298.                 /* how long is it? */
  299.                 DurationOfFrame(Frame,&Duration);
  300.                 ERROR(Duration.Denominator != DURATIONUPDATECLOCKRESOLUTION,PRERR(AllowResume,
  301.                     "CuePlayTrackInfoToPoint:  start time denominator has odd value"));
  302.                 TicksInFrame = Duration.Integer * Duration.Denominator + Duration.Fraction;
  303.                 /* decrement our lead-in counter */
  304.                 AdvancementCounter -= TicksInFrame;
  305.                 /* advance our pointer */
  306.                 TrackInfo->FrameArrayIndex += 1;
  307.             }
  308.  
  309.         /* AdvancementCounter is either 0 or negative.  if it's negative, then we */
  310.         /* need to note that we must delay some before getting the next note */
  311.         TrackInfo->NextFrameCountDown = - AdvancementCounter;
  312.  
  313.         return True;
  314.     }
  315.  
  316.  
  317. /* check to see if the track has finished and can be dropped. */
  318. MyBoolean                        PlayTrackIsItStillActive(PlayTrackInfoRec* TrackInfo)
  319.     {
  320.         OscBankConsCell*    OscBankScan;
  321.  
  322.         CheckPtrExistence(TrackInfo);
  323.  
  324.         /* in order to still be active, the following conditions must be satisfied: */
  325.         /*  - there are still active oscillators. */
  326.         /*  - there are still oscillators in the scanning gap list */
  327.         /*  - there are still notes which haven't been scanned yet */
  328.  
  329.         if (TrackInfo->FrameArrayIndex < TrackInfo->TotalNumberOfFrames)
  330.             {
  331.                 return True;
  332.             }
  333.  
  334.         if (TrackInfo->ScanningGapListHead != NIL)
  335.             {
  336.                 return True;
  337.             }
  338.  
  339.         OscBankScan = TrackInfo->ExecutingOscillatorBanks;
  340.         while (OscBankScan != NIL)
  341.             {
  342.                 if (OscBankScan->StillActive)
  343.                     {
  344.                         return True;
  345.                     }
  346.                 OscBankScan = OscBankScan->Next;
  347.             }
  348.  
  349.         return False;
  350.     }
  351.  
  352.  
  353. /* auxilliary routine which searches a list for a tie source and installs the note */
  354. /* in the list if necessary.  True is returned if it is installed. */
  355. static MyBoolean        SearchForTieSource(OscBankConsCell* OscBankScan,
  356.                                             struct NoteObjectRec* Note, long ScanningGapFrontInEnvelopeTicks,
  357.                                             PlayTrackInfoRec* TrackInfo, float EnvelopeTicksPerDurationTick)
  358.     {
  359.         while (OscBankScan != NIL)
  360.             {
  361.                 FrozenNoteConsCell*        PlaceToPut;
  362.                 long                                    StartAdjust;
  363.  
  364.                 PlaceToPut = NIL;
  365.                 if (OscBankScan->TieTarget == Note)
  366.                     {
  367.                         /* found it */
  368.                      CreateTieContinuationPoint:
  369.                         if (FrozenNoteConsCellFreeList != NIL)
  370.                             {
  371.                                 PlaceToPut = FrozenNoteConsCellFreeList;
  372.                                 FrozenNoteConsCellFreeList = FrozenNoteConsCellFreeList->Next;
  373.                             }
  374.                          else
  375.                             {
  376.                                 PlaceToPut = (FrozenNoteConsCell*)AllocPtrCanFail(
  377.                                     sizeof(FrozenNoteConsCell),"FrozenNoteConsCell");
  378.                                 if (PlaceToPut == NIL)
  379.                                     {
  380.                                         return False;
  381.                                     }
  382.                             }
  383.                     }
  384.                  else
  385.                     {
  386.                         FrozenNoteConsCell*        TargScan;
  387.                         FrozenNoteConsCell*        TargLag;
  388.  
  389.                         /* search tie target things */
  390.                         TargScan = OscBankScan->TieContinuationList;
  391.                         TargLag = NIL;
  392.                         while (TargScan != NIL)
  393.                             {
  394.                                 if (TargScan->TieTarget == Note)
  395.                                     {
  396.                                         /* found one */
  397.                                         goto CreateTieContinuationPoint;
  398.                                     }
  399.                                 TargLag = TargScan;
  400.                                 TargScan = TargScan->Next;
  401.                             }
  402.                     }
  403.                 if (PlaceToPut != NIL)
  404.                     {
  405.                         FrozenNoteConsCell*        InsertScan;
  406.                         FrozenNoteConsCell*        InsertLag;
  407.  
  408.                         /* fill in the fields */
  409.                         PlaceToPut->FrozenNote = FixNoteParameters(
  410.                             TrackInfo->ParameterController,Note,&StartAdjust,
  411.                             TrackInfo->OverallVolumeScaling,EnvelopeTicksPerDurationTick);
  412.                         if (PlaceToPut->FrozenNote == NIL)
  413.                             {
  414.                                 PlaceToPut->Next = FrozenNoteConsCellFreeList;
  415.                                 FrozenNoteConsCellFreeList = PlaceToPut;
  416.                                 return False;
  417.                             }
  418.                         PlaceToPut->ContinuationTime = StartAdjust + ScanningGapFrontInEnvelopeTicks;
  419.                         PlaceToPut->TieTarget = GetNoteTieTarget(Note);
  420.                         /* insert it into the proper place */
  421.                         InsertScan = OscBankScan->TieContinuationList;
  422.                         InsertLag = NIL;
  423.                         while ((InsertScan != NIL) && (InsertScan->ContinuationTime
  424.                             <= PlaceToPut->ContinuationTime))
  425.                             {
  426.                                 InsertLag = InsertScan;
  427.                                 InsertScan = InsertScan->Next;
  428.                             }
  429.                         PlaceToPut->Next = InsertScan;
  430.                         if (InsertLag == NIL)
  431.                             {
  432.                                 OscBankScan->TieContinuationList = PlaceToPut;
  433.                             }
  434.                          else
  435.                             {
  436.                                 InsertLag->Next = PlaceToPut;
  437.                             }
  438.                         /* we found it! */
  439.                         return True;
  440.                     }
  441.                 OscBankScan = OscBankScan->Next;
  442.             }
  443.         return False;
  444.     }
  445.  
  446.  
  447. /* perform one envelope clock cycle update.  if UpdateEnvelopes is true, then */
  448. /* wave data should be generated and envelopes should be updated, otherwise only */
  449. /* note scheduling should be performed. */
  450. MyBoolean                        PlayTrackUpdate(PlayTrackInfoRec* TrackInfo,
  451.                                             MyBoolean UpdateEnvelopes, long NumDurationTicks,
  452.                                             long NumFrames, largefixedsigned* OutputData,
  453.                                             float EnvelopeTicksPerDurationTick,
  454.                                             long ScanningGapFrontInEnvelopeTicks)
  455.     {
  456.         OscBankConsCell*    OscBankScan;
  457.         OscBankConsCell*    OscBankLag;
  458.  
  459.         CheckPtrExistence(TrackInfo);
  460.  
  461.         /* schedule any notes out of the track list into the scanning gap */
  462.         while ((TrackInfo->NextFrameCountDown <= 0)
  463.             && (TrackInfo->FrameArrayIndex < TrackInfo->TotalNumberOfFrames))
  464.             {
  465.                 FrameObjectRec*        Frame;
  466.  
  467.                 /* schedule a frame */
  468.                 Frame = TrackObjectGetFrame(TrackInfo->TrackObject,TrackInfo->FrameArrayIndex);
  469.                 CheckPtrExistence(Frame);
  470.                 TrackInfo->FrameArrayIndex += 1;
  471.                 if (IsThisACommandFrame(Frame))
  472.                     {
  473.                         /* it's a command */
  474.                         ExecuteParamCommandFrame(TrackInfo->ParameterController,Frame);
  475.                     }
  476.                  else
  477.                     {
  478.                         long                            FrameLimit;
  479.                         long                            FrameScan;
  480.                         FractionRec                FrameDuration;
  481.  
  482.                         /* increment the frame counter */
  483.                         DurationOfFrame(Frame,&FrameDuration);
  484.                         ERROR(DURATIONUPDATECLOCKRESOLUTION != FrameDuration.Denominator,
  485.                             PRERR(AllowResume,"PlayTrackUpdate:  strange denominator in frame duration"));
  486.                         TrackInfo->NextFrameCountDown += FrameDuration.Denominator
  487.                             * FrameDuration.Integer + FrameDuration.Fraction;
  488.  
  489.                         /* it's a real note */
  490.                         FrameLimit = NumNotesInFrame(Frame);
  491.                         for (FrameScan = 0; FrameScan < FrameLimit; FrameScan += 1)
  492.                             {
  493.                                 struct NoteObjectRec*    Note;
  494.                                 OscBankConsCell*    NewOscBank;
  495.                                 OscBankConsCell*    LinkingScan;
  496.  
  497.                                 Note = GetNoteFromFrame(Frame,FrameScan);
  498.                                 CheckPtrExistence(Note);
  499.                                 if (GetNoteIsItARest(Note))
  500.                                     {
  501.                                         /* just ignore rests */
  502.                                         goto EndFrameScanPoint; /* this should really be a conditional */
  503.                                     }
  504.  
  505.                                 /* first, scan the oscillator list to see if this is a note that */
  506.                                 /* someone wants to tie to.  if it is, then build a frozen note */
  507.                                 /* structure and add it to the object.  otherwise, build an */
  508.                                 /* oscillator bank and add it to the scanning gap. */
  509.  
  510.                                 /* search all oscillator banks to see if it's a tie target */
  511.                                 if (SearchForTieSource(TrackInfo->ExecutingOscillatorBanks,Note,
  512.                                     ScanningGapFrontInEnvelopeTicks,TrackInfo,
  513.                                     EnvelopeTicksPerDurationTick))
  514.                                     {
  515.                                         goto EndFrameScanPoint;
  516.                                     }
  517.                                 if (SearchForTieSource(TrackInfo->ScanningGapListHead,Note,
  518.                                     ScanningGapFrontInEnvelopeTicks,TrackInfo,
  519.                                     EnvelopeTicksPerDurationTick))
  520.                                     {
  521.                                         goto EndFrameScanPoint;
  522.                                     }
  523.  
  524.                                 /* if we got here, then it's not a tie target */
  525.                                 if (OscBankConsCellFreeList != NIL)
  526.                                     {
  527.                                         NewOscBank = OscBankConsCellFreeList;
  528.                                         OscBankConsCellFreeList = OscBankConsCellFreeList->Next;
  529.                                     }
  530.                                  else
  531.                                     {
  532.                                         NewOscBank = (OscBankConsCell*)AllocPtrCanFail(
  533.                                             sizeof(OscBankConsCell),"OscBankConsCell");
  534.                                         if (NewOscBank == NIL)
  535.                                             {
  536.                                                 return False;
  537.                                             }
  538.                                     }
  539.                                 NewOscBank->OscBank = NewOscBankState(TrackInfo->OscillatorBankTemplate,
  540.                                     &(NewOscBank->StartTime),Note,EnvelopeTicksPerDurationTick);
  541.                                 if (NewOscBank->OscBank == NIL)
  542.                                     {
  543.                                         NewOscBank->Next = OscBankConsCellFreeList;
  544.                                         OscBankConsCellFreeList = NewOscBank;
  545.                                         return False;
  546.                                     }
  547.                                 NewOscBank->StartTime += ScanningGapFrontInEnvelopeTicks; /* fix up start time */
  548.                                 NewOscBank->StillActive = True;
  549.                                 NewOscBank->TieTarget = GetOscStateTieTarget(NewOscBank->OscBank);
  550.                                 NewOscBank->TieContinuationList = NIL;
  551.                                 /* link it in */
  552.                                 LinkingScan = TrackInfo->ScanningGapListTail;
  553.                                 while ((LinkingScan != NIL)
  554.                                     && (LinkingScan->StartTime > NewOscBank->StartTime))
  555.                                     {
  556.                                         LinkingScan = LinkingScan->Previous;
  557.                                     }
  558.                                 if (LinkingScan == NIL)
  559.                                     {
  560.                                         NewOscBank->Previous = NIL;
  561.                                         NewOscBank->Next = TrackInfo->ScanningGapListHead;
  562.                                         if (TrackInfo->ScanningGapListHead != NIL)
  563.                                             {
  564.                                                 TrackInfo->ScanningGapListHead->Previous = NewOscBank;
  565.                                             }
  566.                                         TrackInfo->ScanningGapListHead = NewOscBank;
  567.                                         if (TrackInfo->ScanningGapListTail == NIL)
  568.                                             {
  569.                                                 /* this happens if there were no nodes at all */
  570.                                                 TrackInfo->ScanningGapListTail = NewOscBank;
  571.                                             }
  572.                                     }
  573.                                  else
  574.                                     {
  575.                                         /* insert after Scan */
  576.                                         NewOscBank->Previous = LinkingScan;
  577.                                         NewOscBank->Next = LinkingScan->Next;
  578.                                         LinkingScan->Next = NewOscBank;
  579.                                         if (LinkingScan == TrackInfo->ScanningGapListTail)
  580.                                             {
  581.                                                 /* this happens if Scan was the last element; */
  582.                                                 /* NewNode becomes last element */
  583.                                                 TrackInfo->ScanningGapListTail = NewOscBank;
  584.                                             }
  585.                                     }
  586.  
  587.                              EndFrameScanPoint:
  588.                                 ;
  589.                             }
  590.                     }
  591.             }
  592.  
  593.         /* do timing update */
  594.         TrackInfo->NextFrameCountDown -= NumDurationTicks;
  595.  
  596.         /* update global parameters */
  597.         ExecuteParamUpdate(TrackInfo->ParameterController,NumDurationTicks);
  598.  
  599.         /* generate waveforms, update envelope generators & notes, etc. */
  600.         if (UpdateEnvelopes)
  601.             {
  602.                 /* see if any ties have to be tripped */
  603.                 OscBankScan = TrackInfo->ExecutingOscillatorBanks;
  604.                 while (OscBankScan != NIL)
  605.                     {
  606.                         while ((OscBankScan->TieContinuationList != NIL)
  607.                             && (OscBankScan->TieContinuationList->ContinuationTime
  608.                             <= TrackInfo->ExecutionIndex))
  609.                             {
  610.                                 FrozenNoteConsCell*        Temp;
  611.  
  612.                                 /* yow, let's do this one! */
  613.                                 /* delink */
  614.                                 Temp = OscBankScan->TieContinuationList;
  615.                                 OscBankScan->TieContinuationList
  616.                                     = OscBankScan->TieContinuationList->Next;
  617.                                 /* execute */
  618.                                 if (!ResetOscBankState(OscBankScan->OscBank,Temp->FrozenNote,
  619.                                     EnvelopeTicksPerDurationTick))
  620.                                     {
  621.                                         return False; /* oh, no! */
  622.                                     }
  623.                                 OscBankScan->TieTarget = Temp->TieTarget;
  624.                                 /* clean up */
  625.                                 DisposeFrozenNote(Temp->FrozenNote);
  626.                                 Temp->Next = FrozenNoteConsCellFreeList;
  627.                                 FrozenNoteConsCellFreeList = Temp;
  628.                             }
  629.                         OscBankScan = OscBankScan->Next;
  630.                     }
  631.  
  632.                 /* schedule a note from the scanning gap */
  633.                 while ((TrackInfo->ScanningGapListHead != NIL)
  634.                     && (TrackInfo->ScanningGapListHead->StartTime <= TrackInfo->ExecutionIndex))
  635.                     {
  636.                         OscBankConsCell*    NewConsCell;
  637.  
  638.                         /* yup, schedule the oscillator */
  639.                         NewConsCell = TrackInfo->ScanningGapListHead;
  640.                         TrackInfo->ScanningGapListHead = TrackInfo->ScanningGapListHead->Next;
  641.                         if (TrackInfo->ScanningGapListHead != NIL)
  642.                             {
  643.                                 TrackInfo->ScanningGapListHead->Previous = NIL;
  644.                             }
  645.                          else
  646.                             {
  647.                                 TrackInfo->ScanningGapListTail = NIL;
  648.                             }
  649.                         /* link it in */
  650.                         NewConsCell->Next = TrackInfo->ExecutingOscillatorBanks;
  651.                         TrackInfo->ExecutingOscillatorBanks = NewConsCell;
  652.                         EXECUTE(NewConsCell->Previous = (OscBankConsCell*)0x81818181;)
  653.                     }
  654.  
  655.                 /* increment our scanning gap back edge clock */
  656.                 TrackInfo->ExecutionIndex += 1;
  657.  
  658.                 /* wave generator and envelope update loop */
  659.                 OscBankScan = TrackInfo->ExecutingOscillatorBanks;
  660.                 OscBankLag = NIL;
  661.                 while (OscBankScan != NIL)
  662.                     {
  663.                         OscBankScan->StillActive = !UpdateOscStateBank(OscBankScan->OscBank,
  664.                             NumFrames,OutputData);
  665.                         if (!OscBankScan->StillActive && (OscBankScan->TieContinuationList == NIL))
  666.                             {
  667.                                 OscBankConsCell*    Temp;
  668.  
  669.                                 /* not tied to anybody, so kill it */
  670.                                 DisposeOscStateBank(OscBankScan->OscBank);
  671.                                 if (OscBankLag == NIL)
  672.                                     {
  673.                                         TrackInfo->ExecutingOscillatorBanks = OscBankScan->Next;
  674.                                     }
  675.                                  else
  676.                                     {
  677.                                         OscBankLag->Next = OscBankScan->Next;
  678.                                     }
  679.                                 Temp = OscBankScan;
  680.                                 OscBankScan = OscBankScan->Next;
  681.                                 Temp->Next = OscBankConsCellFreeList;
  682.                                 OscBankConsCellFreeList = Temp;
  683.                             }
  684.                          else
  685.                             {
  686.                                 OscBankLag = OscBankScan;
  687.                                 OscBankScan = OscBankScan->Next;
  688.                             }
  689.                     }
  690.             }
  691.  
  692.         return True;
  693.     }
  694.